/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
/*
 * bocciawii
 * Copyright (C) Grupo de trabajo ULE 2010 <ulewii@googlegroups.com>
 * 
 * bocciawii is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * bocciawii is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "camara.h"

Camara::Camara(float init_x, float init_z, float x_cen, float z_cen)
{
	x_centro = x_cen;
	z_centro = z_cen;
	activa = CAMARA_PRIMERA_PERSONA;
	box_activo = 0;
	
	datos_primera = new float[3];
	datos_primera[0] = x_centro;
	datos_primera[1] = 0.0;
	datos_primera[2] = z_centro;

	posiciones_primera = new box[6];
	for (int i = 0; i < 6; i++) 
	{
		posiciones_primera[i].x = init_x + i;
		posiciones_primera[i].y = 1.2;
		posiciones_primera[i].z = init_z;
	}

	datos_estadio = new float[3];
	datos_estadio[0] = 0.0;
	datos_estadio[1] = 1.0;
	datos_estadio[2] = 5.0;

	datos_aerea = new float[4];
	datos_aerea[0] = x_centro;
	datos_aerea[1] = 10.0;
	datos_aerea[2] = z_centro;
	datos_aerea[3] = 1.0;

	CalculaCamara ();
}


Camara::~Camara()
{	
}

void Camara::Mirar()
{
	gluLookAt(posx, posy, posz, tox, toy, toz, upx, upy, upz);
}

void Camara::ActivaCamara(int cam, int opcion)
{
	
	if (activa!=cam)
	{
		if (cam == CAMARA_ESTADIO)
		{
			activa = CAMARA_ESTADIO;
			datos_estadio[0] = 0.0;
			datos_estadio[1] = 1.0;
			datos_estadio[2] = 2.5;
		}
		else if (cam == CAMARA_AEREA)
		{
			activa = CAMARA_AEREA;
			datos_aerea[0] = x_centro;
			datos_aerea[1] = 8.0;
			datos_aerea[2] = z_centro;
			datos_aerea[3] = 1.0;
		}
		else if (cam == CAMARA_PRIMERA_PERSONA)
		{
			activa = CAMARA_PRIMERA_PERSONA;
			/* Como la de primera persona la vamos a usar únicamente con
			 parámetros de box, dejaremos que inicialice los valores
			 el procedimiento que elige box */
//			datos_primera[0] = x_centro;
//			datos_primera[1] = 0.0;
//			datos_primera[2] = z_centro;
			/** En este punto hay que recoger la opción, que contiene el índice
			 *  de la "caja" desde la que va a lanzar el jugador. Esas cajas
			 *  tienen posiciones fijas y las podemos consultar en un array que
			 *  ya definiré. La posición de la cámara se coge de ahí.
			 */
		} // if (cam ==  )
		
		CalculaCamara ();
	} // if (activa != cam)
}

void Camara::EligeBox(int b) 
{
	if ((b > 0) && (b < 7) && (b != (box_activo+1)))
	{
		box_activo = b - 1;
		datos_primera[0] = x_centro;
		datos_primera[1] = 0.0;
		datos_primera[2] = z_centro;
	}
	
	CalculaCamara ();
}

void Camara::GestionaEvento(int evento, float factorx, float factory, long int delta)
{
	switch(activa) {
		case CAMARA_PRIMERA_PERSONA:
			switch(evento) {
				case N:
					if (datos_primera[1] < MAXPRIMERA)
						datos_primera[1] += DESPLAZAMIENTO * factory;
					break;
				case S:
					if (datos_primera[1] > MINPRIMERA)
						datos_primera[1] -= DESPLAZAMIENTO * factory;
					break;
				case E:
					if (datos_primera[0] < MAXLATERAL)
						datos_primera[0] += DESPLAZAMIENTO * factorx;
					break;
				case O:
					if (datos_primera[0] > -MAXLATERAL)
						datos_primera[0] -= DESPLAZAMIENTO * factorx;
					break;
				case NO:
					if (datos_primera[1] < MAXPRIMERA)
						datos_primera[1] += DESPLAZAMIENTO * factory;
					if (datos_primera[0] > -MAXLATERAL)
						datos_primera[0] -= DESPLAZAMIENTO * factorx;
					break;
				case SO:
					if (datos_primera[1] > MINPRIMERA)
						datos_primera[1] -= DESPLAZAMIENTO * factory;
					if (datos_primera[0] > -MAXLATERAL)
						datos_primera[0] -= DESPLAZAMIENTO * factorx;
					break;
				case NE:
					if (datos_primera[1] < MAXPRIMERA)
						datos_primera[1] += DESPLAZAMIENTO * factory;
					if (datos_primera[0] < MAXLATERAL)
						datos_primera[0] += DESPLAZAMIENTO * factorx;
					break;
				case SE:
					if (datos_primera[1] > MINPRIMERA)
						datos_primera[1] -= DESPLAZAMIENTO * factory;
					if (datos_primera[0] < MAXLATERAL)
						datos_primera[0] += DESPLAZAMIENTO * factorx;
					break;
			} // switch(evento)
			//
		break;
			
		case CAMARA_ESTADIO:
			switch(evento) {
				case N:
					if (datos_estadio[2] < MAXALTURA)
						datos_estadio[2] += DESPLAZAMIENTO * factory * 2;
					break;
				case S:
					if (datos_estadio[2] > MINSUELO)
						datos_estadio[2] -= DESPLAZAMIENTO * factory * 2;
					break;
				case E:
					datos_estadio[0] += VANGULAR * factorx;
					break;
				case O:
					datos_estadio[0] -= VANGULAR * factorx;
					break;
				case NO:
					if (datos_estadio[2] < MAXALTURA)
						datos_estadio[2] += DESPLAZAMIENTO * factory * 2;
					datos_estadio[0] -= VANGULAR * factorx;
					break;
				case SO:
					if (datos_estadio[2] > MINSUELO)
						datos_estadio[2] -= DESPLAZAMIENTO * factory * 2;
					datos_estadio[0] -= VANGULAR * factorx;
					break;
				case NE:
					if (datos_estadio[2] < MAXALTURA)
						datos_estadio[2] += DESPLAZAMIENTO * factory * 2;
					datos_estadio[0] += VANGULAR * factorx;
					break;
				case SE:
					if (datos_estadio[2] > MINSUELO)
						datos_estadio[2] -= DESPLAZAMIENTO * factory * 2;
					datos_estadio[0] += VANGULAR * factorx;
					break;
				case ZOOMMAS:
					if (datos_estadio[1] > MAXZOOM)
						datos_estadio[1] -= DESPLAZAMIENTO * 2;
					break;
				case ZOOMMENOS:
					if (datos_estadio[1] < MINZOOM)
						datos_estadio[1] += DESPLAZAMIENTO * 2;
					break;
			} // switch(evento)
			
		break;
		case CAMARA_AEREA:
			switch(evento) {
				case N:
					if (datos_aerea[2] > posiciones_primera[0].z - 12)
						datos_aerea[2] -= DESPLAZAMIENTO * factory;
					break;
				case S:
					if (datos_aerea[2] < posiciones_primera[0].z)
						datos_aerea[2] += DESPLAZAMIENTO * factory;
					break;
				case E:
					if (datos_aerea[0] < posiciones_primera[0].x + 6)
						datos_aerea[0] += DESPLAZAMIENTO * factorx;
					break;
				case O:
					if (datos_aerea[0] > posiciones_primera[0].x)
						datos_aerea[0] -= DESPLAZAMIENTO * factorx;
					break;
				case NO:
					if (datos_aerea[2] > posiciones_primera[0].z - 12)
						datos_aerea[2] -= DESPLAZAMIENTO * factory;
					if (datos_aerea[0] > posiciones_primera[0].x)
						datos_aerea[0] -= DESPLAZAMIENTO * factorx;
					break;
				case SO:
					if (datos_aerea[2] < posiciones_primera[0].z)
						datos_aerea[2] += DESPLAZAMIENTO * factory;
					if (datos_aerea[0] > posiciones_primera[0].x)
						datos_aerea[0] -= DESPLAZAMIENTO * factorx;
					break;
				case NE:
					if (datos_aerea[2] > posiciones_primera[0].z - 12)
						datos_aerea[2] -= DESPLAZAMIENTO * factory;
					if (datos_aerea[0] < posiciones_primera[0].x + 6)
						datos_aerea[0] += DESPLAZAMIENTO * factorx;
					break;
				case SE:
					if (datos_aerea[2] < posiciones_primera[0].z)
						datos_aerea[2] += DESPLAZAMIENTO * factory;
					if (datos_aerea[0] < posiciones_primera[0].x + 6)
						datos_aerea[0] += DESPLAZAMIENTO * factorx;
					break;
				case ZOOMMAS:
					if (datos_aerea[3] > MAXZOOM_AEREA)
						datos_aerea[3] -= DESPLAZAMIENTO * 2;
					break;
				case ZOOMMENOS:
					if (datos_aerea[3] < MINZOOM_AEREA)
						datos_aerea[3] += DESPLAZAMIENTO * 2;
					break;
			} // switch(evento)
			
		break;
	} // switch(activa)
	
	CalculaCamara ();
}

void Camara::CalculaCamara()
{
	switch(activa) {
		case CAMARA_PRIMERA_PERSONA:
			posx = posiciones_primera[box_activo].x;
			posy = posiciones_primera[box_activo].y;
			posz = posiciones_primera[box_activo].z;
			upx = upz = 0.0;
			upy = 1.0;
			tox = datos_primera[0];
			toy = datos_primera[1];
			toz = datos_primera[2];
			break;
		case CAMARA_ESTADIO:
			posx = datos_estadio[1] * EJEMENOR * sin(datos_estadio[0] * M_PI / 180) + x_centro;
			posy = datos_estadio[2] * datos_estadio[1];
			posz = datos_estadio[1] * EJEMAYOR * cos(datos_estadio[0] * M_PI / 180) + z_centro;
			tox = x_centro;
			toy = 0.0;
			toz = z_centro;
			upx = upz = 0.0;
			upy = 1.0;
			break;
		case CAMARA_AEREA:
			posx = datos_aerea[0];
			posz = datos_aerea[2];
			posy = datos_aerea[1] * datos_aerea[3];
			tox = datos_aerea[0];
			toy = 0;
			toz = datos_aerea[2];
			upx = upy = 0.0;
			upz = -1.0;
			break;
	} // switch(activa)	
}

float* Camara::GetPosicionBox()
{
	float* p = new float[3];
	p[0] = posiciones_primera[box_activo].x;
	p[1] = posiciones_primera[box_activo].y;
	p[2] = posiciones_primera[box_activo].z;
	return p;
}

float* Camara::GetDireccion()
{
	float* d = new float[3];
	/*
	 La dirección interesa tanto en primera como en táctica, 
	 en estadio no parece lógico dibujarla, de todas maneras
	 dejo esto comentado y no añado código
	 */
//	if (activa == CAMARA_PRIMERA_PERSONA) {
		d[0] = datos_primera[0] - posiciones_primera[box_activo].x;
		d[1] = 0.0; //datos_primera[1] - posiciones_primera[box_activo].y;
		d[2] = datos_primera[2] - posiciones_primera[box_activo].z;
//	} else {
//		d[0] = d[1] = d[2] = 0.0;
//	}
	
	float* u = GetUnitario(d);
	// printf("Vector de dirección: (%f, %f, %f)", u[0], u[1], u[2]);
	// printf(", módulo = %f\n", sqrt(pow(u[0], 2) + pow(u[1], 2) + pow(u[2], 2)));
	return u;
}

float* GetUnitario(float* vector)
{
	float* unitario = new float[3];
	float modulo = sqrt(pow(vector[0], 2) + pow(vector[1], 2) + pow(vector[2], 2));
	unitario[0] = vector[0] / modulo;
	unitario[1] = vector[1] / modulo;
	unitario[2] = vector[2] / modulo;
	return unitario;
}